/*************************************************************************************
 *
 *  Revolution Engine
 *  Copyright (C) 2009 Felipe Apablaza
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ************************************************************************************/


//---------------------------------------------------------
//
//  File:	ObjRef.hpp
//  Desc:	IObject's smart pointer template class.
//			Idented to be used by the Impl's inline 
//			wrappers.
//
//---------------------------------------------------------

#ifndef __REVENG_OBJREF_HPP__
#define __REVENG_OBJREF_HPP__

#include <cstddef>

namespace RevEng
{
	//Referencia a un objeto. Sera usada para el patron Bridge.
	template<typename Class>
	class ObjRef
	{
	private:
		Class *m_pObject;

	public:
		//
		ObjRef() : m_pObject(NULL)
		{
		}

		//Adquiere una instancia
		ObjRef(Class *Obj) : m_pObject(Obj)
		{
			if (m_pObject)
				m_pObject->AddRef();
		}

		//Adquiere una instancia de otra referencia
		ObjRef(const ObjRef<Class> &Ref) : m_pObject(Ref.m_pObject)
		{
			if (m_pObject)
				m_pObject->AddRef();
		}

		//Libera la instancia 
		~ObjRef()
		{
			if (m_pObject)
				m_pObject->Release();
		}


		//Cambia la instancia de esta referencia por la de otra referencia
		ObjRef<Class>& operator= (const ObjRef<Class>& ObjRef)
		{
			if (m_pObject)
				m_pObject->Release();

			m_pObject = ObjRef.m_pObject;

			if (m_pObject)
				m_pObject->AddRef();

			return *this;
		}


		//Cambia la instancia de esta referencia por la de otra referencia
		ObjRef<Class>& operator= (Class* Obj)
		{
			if (m_pObject)
				m_pObject->Release();

			m_pObject = Obj;

			if (m_pObject)
				m_pObject->AddRef();

			return *this;
		}

		//Devuelve el objeto almacenado.
		operator Class* ()
		{
			return m_pObject;
		}


		operator const Class* ()
		{
			return const_cast<Class*>(m_pObject);
		}


		operator Class*() const
		{
			return const_cast<Class*>(m_pObject);
		}

		operator const Class*() const
		{
			return const_cast<Class*>(m_pObject);
		}

		//Aplica un metodo del objeto almacenado
		Class* operator-> ()
		{
			return m_pObject;
		}

		const Class* operator-> () const
		{
			return m_pObject;
		}
	};
}

#endif
